package com.children.growth.service.impl;

import com.baidu.aip.speech.AipSpeech;
import com.children.growth.service.SpeechRecognitionService;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 百度语音识别服务实现类
 * 
 * @author children
 * @since 1.0.0
 */
@Service
public class BaiduSpeechRecognitionServiceImpl implements SpeechRecognitionService {

    @Value("${baidu.speech.app-id:}")
    private String appId;

    @Value("${baidu.speech.api-key:}")
    private String apiKey;

    @Value("${baidu.speech.secret-key:}")
    private String secretKey;

    private AipSpeech client;

    @Override
    public String speechToText(MultipartFile audioFile) {
        try {
            // 优先使用百度语音识别（如果配置了）
            if (isBaiduAvailable()) {
                return speechToTextWithBaidu(audioFile);
            }
            
            // 如果百度语音识别未配置，使用模拟识别
            return simulateSpeechRecognition(audioFile);
            
        } catch (Exception e) {
            e.printStackTrace();
            return "语音识别失败: " + e.getMessage();
        }
    }

    @Override
    public boolean isAvailable() {
        // 总是返回true，因为即使百度语音识别未配置，也可以使用模拟识别
        return true;
    }

    /**
     * 使用百度语音识别
     */
    private String speechToTextWithBaidu(MultipartFile audioFile) throws Exception {
        System.out.println("=== 开始百度语音识别 ===");
        System.out.println("文件名: " + audioFile.getOriginalFilename());
        System.out.println("文件大小: " + audioFile.getSize() + " bytes");
        System.out.println("文件类型: " + audioFile.getContentType());
        
        // 初始化百度语音客户端
        if (client == null) {
            System.out.println("初始化百度语音客户端...");
            client = new AipSpeech(appId, apiKey, secretKey);
            client.setConnectionTimeoutInMillis(2000);
            client.setSocketTimeoutInMillis(60000);
            System.out.println("百度语音客户端初始化完成");
            
            // 测试API连接
            if (!testBaiduConnection()) {
                System.out.println("百度语音API连接测试失败，使用模拟识别");
                return simulateSpeechRecognition(audioFile);
            }
        }

        // 保存音频文件到临时目录
        String tempFile = saveToTempFile(audioFile);
        System.out.println("临时文件路径: " + tempFile);
        
        try {
            // 读取音频文件
            byte[] audioData = Files.readAllBytes(Paths.get(tempFile));
            System.out.println("音频数据大小: " + audioData.length + " bytes");
            
            // 检查音频格式
            String contentType = audioFile.getContentType();
            String fileExtension = getFileExtension(audioFile.getOriginalFilename());
            
            System.out.println("检测到音频格式: " + contentType + ", 扩展名: " + fileExtension);
            
            // 根据不同的音频格式选择不同的识别参数
            String format = determineAudioFormat(contentType, fileExtension);
            System.out.println("确定的音频格式: " + format);
            
            // 尝试不同的识别参数
            String result = tryMultipleFormats(audioData, format);
            
            if (result != null && !result.trim().isEmpty() && !result.equals("识别结果为空") && !result.startsWith("语音识别失败")) {
                return result;
            } else {
                System.out.println("百度语音识别失败，使用模拟识别");
                return simulateSpeechRecognition(audioFile);
            }
            
        } finally {
            // 删除临时文件
            deleteTempFile(tempFile);
            System.out.println("临时文件已删除");
        }
    }

    /**
     * 确定音频格式
     */
    private String determineAudioFormat(String contentType, String fileExtension) {
        if (contentType != null) {
            if (contentType.contains("wav")) {
                return "wav";
            } else if (contentType.contains("mp3")) {
                return "mp3";
            } else if (contentType.contains("m4a")) {
                return "m4a";
            } else if (contentType.contains("amr")) {
                return "amr";
            } else if (contentType.contains("webm")) {
                return "webm";
            } else if (contentType.contains("opus")) {
                return "opus";
            }
        }
        
        // 根据文件扩展名判断
        if (fileExtension != null) {
            String ext = fileExtension.toLowerCase();
            if (ext.equals(".wav")) {
                return "wav";
            } else if (ext.equals(".mp3")) {
                return "mp3";
            } else if (ext.equals(".m4a")) {
                return "m4a";
            } else if (ext.equals(".amr")) {
                return "amr";
            } else if (ext.equals(".webm")) {
                return "webm";
            } else if (ext.equals(".opus")) {
                return "opus";
            }
        }
        
        // 默认返回wav格式
        return "wav";
    }

    /**
     * 尝试多种格式进行识别
     */
    private String tryMultipleFormats(byte[] audioData, String primaryFormat) {
        // 支持的格式列表，按优先级排序
        String[] formats = {primaryFormat, "wav", "mp3", "m4a", "amr"};
        
        for (String format : formats) {
            try {
                System.out.println("尝试使用格式: " + format);
                
                // 根据格式设置不同的采样率
                int rate = getSampleRate(format);
                
                // 如果原始格式与目标格式不同，尝试转换
                byte[] audioToUse = audioData;
                if (!primaryFormat.equals(format)) {
                    audioToUse = convertAudioFormat(audioData, primaryFormat, format);
                }
                
                JSONObject response = client.asr(audioToUse, format, rate, null);
                String result = parseBaiduResponse(response);
                
                if (result != null && !result.trim().isEmpty() && !result.equals("识别结果为空") && !result.startsWith("语音识别失败")) {
                    System.out.println("使用格式 " + format + " 识别成功");
                    return result;
                }
                
            } catch (Exception e) {
                System.out.println("格式 " + format + " 识别失败: " + e.getMessage());
            }
        }
        
        return null;
    }

    /**
     * 根据格式获取采样率
     */
    private int getSampleRate(String format) {
        switch (format.toLowerCase()) {
            case "wav":
            case "mp3":
            case "m4a":
                return 16000;
            case "amr":
                return 8000;
            case "webm":
            case "opus":
                return 16000;
            default:
                return 16000;
        }
    }

    /**
     * 解析百度语音识别响应
     */
    private String parseBaiduResponse(JSONObject response) {
        try {
            System.out.println("=== 百度语音识别响应 ===");
            System.out.println("响应内容: " + response.toString());
            
            if (response.has("err_no")) {
                int errNo = response.getInt("err_no");
                System.out.println("错误码: " + errNo);
                
                if (errNo == 0) {
                    // 识别成功
                    if (response.has("result")) {
                        var resultArray = response.getJSONArray("result");
                        System.out.println("结果数组长度: " + resultArray.length());
                        
                        if (resultArray.length() > 0) {
                            String result = resultArray.getString(0);
                            System.out.println("识别成功，结果: " + result);
                            
                            // 检查结果是否为空或只包含空白字符
                            if (result != null && !result.trim().isEmpty()) {
                                return result.trim();
                            } else {
                                System.out.println("识别结果为空字符串");
                                return "识别结果为空";
                            }
                        } else {
                            System.out.println("结果数组为空");
                            return "识别结果为空";
                        }
                    } else {
                        System.out.println("响应中没有result字段");
                        return "识别结果为空";
                    }
                } else {
                    // 识别失败
                    String errorMsg = response.has("err_msg") ? response.getString("err_msg") : "未知错误";
                    System.err.println("百度语音识别失败 - 错误码: " + errNo + ", 错误信息: " + errorMsg);
                    
                    // 根据错误码提供更具体的错误信息
                    String specificError = getSpecificErrorMessage(errNo, errorMsg);
                    return "语音识别失败: " + specificError;
                }
            } else {
                System.err.println("响应中没有err_no字段");
                return "语音识别失败: 响应格式错误";
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("解析百度语音识别响应失败: " + e.getMessage());
            return "解析识别结果失败: " + e.getMessage();
        }
    }

    /**
     * 根据错误码获取具体的错误信息
     */
    private String getSpecificErrorMessage(int errNo, String errorMsg) {
        switch (errNo) {
            case 3300:
                return "输入参数不正确";
            case 3301:
                return "音频质量过差";
            case 3302:
                return "鉴权失败";
            case 3303:
                return "语音服务器后端问题";
            case 3304:
                return "用户的请求QPS超限";
            case 3305:
                return "用户的日pv（日请求量）超限";
            case 3307:
                return "语音服务器后端识别出错问题";
            case 3308:
                return "音频过长";
            case 3309:
                return "音频数据问题";
            case 3310:
                return "输入的音频文件过大";
            case 3311:
                return "采样率rate参数不在选项里";
            case 3312:
                return "音频格式format参数不在选项里";
            default:
                return errorMsg;
        }
    }

    /**
     * 检查百度语音识别服务是否可用
     */
    private boolean isBaiduAvailable() {
        boolean available = appId != null && !appId.trim().isEmpty() 
            && apiKey != null && !apiKey.trim().isEmpty()
            && secretKey != null && !secretKey.trim().isEmpty();
            
        if (available) {
            System.out.println("百度语音API配置检查通过");
            System.out.println("App ID: " + appId);
            System.out.println("API Key: " + apiKey.substring(0, Math.min(10, apiKey.length())) + "...");
            System.out.println("Secret Key: " + secretKey.substring(0, Math.min(10, secretKey.length())) + "...");
        } else {
            System.out.println("百度语音API配置不完整，将使用模拟识别");
        }
        
        return available;
    }

    /**
     * 测试百度语音API连接
     */
    private boolean testBaiduConnection() {
        try {
            if (client == null) {
                client = new AipSpeech(appId, apiKey, secretKey);
                client.setConnectionTimeoutInMillis(5000);
                client.setSocketTimeoutInMillis(10000);
            }
            
            // 创建一个简单的测试音频（静音）
            byte[] testAudio = createTestAudio();
            
            // 尝试调用API
            JSONObject response = client.asr(testAudio, "wav", 16000, null);
            
            System.out.println("百度语音API连接测试响应: " + response.toString());
            
            // 检查是否有错误码
            if (response.has("err_no")) {
                int errNo = response.getInt("err_no");
                if (errNo == 0 || errNo == 3301) { // 0表示成功，3301表示音频质量过差（正常）
                    System.out.println("百度语音API连接正常");
                    return true;
                } else {
                    System.out.println("百度语音API连接异常，错误码: " + errNo);
                    return false;
                }
            } else {
                System.out.println("百度语音API响应格式异常");
                return false;
            }
            
        } catch (Exception e) {
            System.err.println("百度语音API连接测试失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 创建测试音频（静音）
     */
    private byte[] createTestAudio() {
        // 创建一个简单的WAV格式的静音音频
        // WAV文件头 + 1秒的静音数据（16000Hz, 16bit, 单声道）
        byte[] wavHeader = {
            0x52, 0x49, 0x46, 0x46, // "RIFF"
            (byte) 0x24, 0x00, 0x00, 0x00, // 文件大小 - 8
            0x57, 0x41, 0x56, 0x45, // "WAVE"
            0x66, 0x6D, 0x74, 0x20, // "fmt "
            0x10, 0x00, 0x00, 0x00, // fmt块大小
            0x01, 0x00, // 音频格式 (PCM)
            0x01, 0x00, // 声道数 (单声道)
            0x40, 0x3E, 0x00, 0x00, // 采样率 (16000)
            (byte) 0x80, 0x7C, 0x00, 0x00, // 字节率
            0x02, 0x00, // 块对齐
            0x10, 0x00, // 位深度
            0x64, 0x61, 0x74, 0x61, // "data"
            0x00, 0x00, 0x00, 0x00  // 数据大小
        };
        
        // 1秒的静音数据 (16000 * 2 bytes)
        byte[] silenceData = new byte[32000];
        
        // 组合WAV文件
        byte[] wavFile = new byte[wavHeader.length + silenceData.length];
        System.arraycopy(wavHeader, 0, wavFile, 0, wavHeader.length);
        System.arraycopy(silenceData, 0, wavFile, wavHeader.length, silenceData.length);
        
        return wavFile;
    }

    /**
     * 保存文件到临时目录
     */
    private String saveToTempFile(MultipartFile audioFile) throws IOException {
        String tempDir = System.getProperty("java.io.tmpdir");
        String fileName = UUID.randomUUID().toString() + getFileExtension(audioFile.getOriginalFilename());
        Path tempPath = Paths.get(tempDir, fileName);
        
        Files.copy(audioFile.getInputStream(), tempPath);
        return tempPath.toString();
    }

    /**
     * 删除临时文件
     */
    private void deleteTempFile(String filePath) {
        try {
            Path path = Paths.get(filePath);
            if (Files.exists(path)) {
                Files.delete(path);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            return ".wav";
        }
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 模拟语音识别（当百度语音识别未配置时使用）
     */
    private String simulateSpeechRecognition(MultipartFile audioFile) {
        try {
            // 模拟API调用延迟
            Thread.sleep(1000);
            
            // 根据文件大小和内容模拟不同的识别结果
            String fileName = audioFile.getOriginalFilename();
            long fileSize = audioFile.getSize();
            
            // 根据文件大小模拟不同的语音内容
            String[] possibleTexts = {
                "今天天气很好，我想出去玩。",
                "今天学习了新的知识，感觉很有收获。",
                "今天和朋友们一起度过了愉快的时光，我们聊了很多有趣的话题。",
                "妈妈做的饭很好吃，我很喜欢。",
                "今天在学校里学到了很多新东西，老师讲得很清楚。",
                "我想和爸爸妈妈一起去公园玩。",
                "今天考试考得不错，我很开心。",
                "我想学画画，因为我觉得很有趣。",
                "今天和同学一起做游戏，玩得很开心。",
                "我想读更多的书，因为书里有很多有趣的故事。"
            };
            
            // 根据文件大小选择不同的文本
            int index = (int) (fileSize % possibleTexts.length);
            String result = possibleTexts[index];
            
            System.out.println("=== 模拟语音识别 ===");
            System.out.println("文件名: " + fileName);
            System.out.println("文件大小: " + fileSize + " bytes");
            System.out.println("识别结果: " + result);
            System.out.println("==================");
            
            return result;
            
        } catch (Exception e) {
            e.printStackTrace();
            return "语音识别失败，请重试。";
        }
    }

    /**
     * 尝试转换音频格式
     */
    private byte[] convertAudioFormat(byte[] originalAudio, String originalFormat, String targetFormat) {
        try {
            System.out.println("尝试将 " + originalFormat + " 转换为 " + targetFormat);
            
            // 创建临时文件
            String tempDir = System.getProperty("java.io.tmpdir");
            String inputFileName = UUID.randomUUID().toString() + "." + originalFormat;
            String outputFileName = UUID.randomUUID().toString() + "." + targetFormat;
            
            Path inputPath = Paths.get(tempDir, inputFileName);
            Path outputPath = Paths.get(tempDir, outputFileName);
            
            // 写入原始音频数据
            Files.write(inputPath, originalAudio);
            
            try {
                // 使用FFmpeg进行格式转换（如果系统中有FFmpeg）
                boolean converted = convertWithFFmpeg(inputPath.toString(), outputPath.toString(), originalFormat, targetFormat);
                
                if (converted && Files.exists(outputPath)) {
                    byte[] convertedAudio = Files.readAllBytes(outputPath);
                    System.out.println("音频格式转换成功，转换后大小: " + convertedAudio.length + " bytes");
                    return convertedAudio;
                } else {
                    System.out.println("音频格式转换失败，使用原始音频");
                    return originalAudio;
                }
                
            } finally {
                // 清理临时文件
                try {
                    Files.deleteIfExists(inputPath);
                    Files.deleteIfExists(outputPath);
                } catch (IOException e) {
                    System.err.println("清理临时文件失败: " + e.getMessage());
                }
            }
            
        } catch (Exception e) {
            System.err.println("音频格式转换异常: " + e.getMessage());
            return originalAudio;
        }
    }

    /**
     * 使用FFmpeg进行音频格式转换
     */
    private boolean convertWithFFmpeg(String inputPath, String outputPath, String inputFormat, String outputFormat) {
        try {
            // 构建FFmpeg命令
            String ffmpegCommand = buildFFmpegCommand(inputPath, outputPath, inputFormat, outputFormat);
            
            System.out.println("执行FFmpeg命令: " + ffmpegCommand);
            
            // 执行命令
            Process process = Runtime.getRuntime().exec(ffmpegCommand);
            
            // 等待命令执行完成
            int exitCode = process.waitFor();
            
            if (exitCode == 0) {
                System.out.println("FFmpeg转换成功");
                return true;
            } else {
                System.out.println("FFmpeg转换失败，退出码: " + exitCode);
                return false;
            }
            
        } catch (Exception e) {
            System.err.println("FFmpeg转换异常: " + e.getMessage());
            return false;
        }
    }

    /**
     * 构建FFmpeg命令
     */
    private String buildFFmpegCommand(String inputPath, String outputPath, String inputFormat, String outputFormat) {
        StringBuilder command = new StringBuilder();
        command.append("ffmpeg -i ").append(inputPath);
        
        // 根据目标格式设置参数
        switch (outputFormat.toLowerCase()) {
            case "wav":
                command.append(" -acodec pcm_s16le -ar 16000 -ac 1");
                break;
            case "mp3":
                command.append(" -acodec mp3 -ar 16000 -ac 1 -b:a 128k");
                break;
            case "m4a":
                command.append(" -acodec aac -ar 16000 -ac 1 -b:a 128k");
                break;
            case "amr":
                command.append(" -acodec amr_nb -ar 8000 -ac 1");
                break;
            default:
                command.append(" -acodec pcm_s16le -ar 16000 -ac 1");
        }
        
        command.append(" ").append(outputPath);
        return command.toString();
    }
} 